#NoEnv
#include ScreenCapture.ahk

#Include Crypt.ahk
#Include CryptConst.ahk
#Include CryptFoos.ahk

#Include py_socket.ahk

#include HTTPRequest.ahk

; ターゲットアプリ名
moe_win = ahk_class Master of Epic -The ResonanceAge Universe-
Unreview_count := 0
AryUnreview := {}
AryUnreviewBMP := {}

TotalItems := 0

; local_debug := True

; ソフトウェア バージョンチェックサイトのURL
mainte_Server := "http://yamvc-mainte.appspot.com/verify_yamvc_ver"     ; 本番環境

; 誤字修正定義ファイル バージョンチェックサイトのURL
subst_mainte_Server := "http://yamvc-mainte.appspot.com/verify_substitutions" ; 本番環境
getsubst_mainte_Server := "http://yamvc-mainte.appspot.com/get_substitutions" ; 本番環境

; 誤字修正定義ファイル パッチ提案サイトのURL
postsubst_mainte_Server := "http://yamvc-mainte.appspot.com/put_substitutions" ; 本番環境

if (local_debug) { ; 家の - デバッグ用
    mainte_Server :=            "http://localhost:8081/verify_yamvc_ver"
    subst_mainte_Server :=      "http://localhost:8081/verify_substitutions"
    getsubst_mainte_Server :=   "http://localhost:8081/get_substitutions"
    postsubst_mainte_Server :=  "http://localhost:8081/put_substitutions"
}

if (check_software_update()) {
    TrayTip,, ソフトウェア更新チェック
    MsgBox, 0x03, yamvc更新確認, ソフトウェアの更新があります。サイトを開きますか？, 10
    IfMsgBox Yes
    {
        Run, https://code.google.com/p/moe-vendor-capture/downloads/list
        ExitApp
    }
    IfMsgBox Cancel
    {
        ExitApp
    }
    TrayTip,,
}

new_subst_ver := check_subst_update()

str_magic = __cr_magic__%COMPUTERNAME%

CoordMode, Mouse, Screen     ; Make 0,0 the top-left of screen
CoordMode, ToolTip, Screen
CoordMode, Pixel, Screen

CaptureMode := 0

AryJob := {}
AryJobText := {}
job_count := 0
last_job =
reqdlg_cnt := 0
;SetWorkingDir, %A_ScriptDir%
topLeftCoordActive = 1   ; 0 = The top-left coordinate is active; 1 = The bottom-right coordinate is active
moveBothCorners    = 0   ; 1 = Move both corners at the same time
bothCornersHeight  = 0   ; The height of the capture box with in "move both corners" mode
bothCornersWidth   = 0   ; The width of the capture box with in "move both corners" mode
BOX_UPDATE_RATE    = 10  ; The update rate of the capture box (ms)
MONO_FILTER = Utils\b2m32010\BMP2MONO.exe

    ; OCR対象領域の設定をINIファイルから設定を読み込む
    mvinifile = mvcap.ini
    IniRead, x1,                    %mvinifile%, Coord, x1
    IniRead, y1,                    %mvinifile%, Coord, y1
    IniRead, x2,                    %mvinifile%, Coord, x2
    IniRead, y2,                    %mvinifile%, Coord, y2
    IniRead, ChkJpg,                %mvinifile%, Coord, ChkJpg
    IniRead, ChkOCR,                %mvinifile%, Coord, ChkOCR
    IniRead, ChkAppend_OneText,     %mvinifile%, Coord, ChkAppend_OneText
    IniRead, TxtAppend_Filename,    %mvinifile%, Coord, TxtAppend_Filename
    IniRead, ChkAdditionalCap,      %mvinifile%, Coord, ChkAdditionalCap
    IniRead, AddX1,                 %mvinifile%, Coord, AddX1
    IniRead, AddY1,                 %mvinifile%, Coord, AddY1
    IniRead, AddX2,                 %mvinifile%, Coord, AddX2
    IniRead, AddY2,                 %mvinifile%, Coord, AddY2
    IniRead, CapHotkey,             %mvinifile%, Coord, CapHotkey
    IniRead, AdjustX,               %mvinifile%, Coord, AdjustX
    IniRead, Append_HTML,           %mvinifile%, Coord, Append_HTML
    IniRead, Append_BaseDir,        %mvinifile%, Coord, Append_BaseDir
    IniRead, ChkDebug,              %mvinifile%, Coord, ChkDebug
    IniRead, MoE_UserdataDir,       %mvinifile%, Coord, MoE_UserdataDir
    IniRead, Chk_Excel,             %mvinifile%, Coord, Chk_Excel
    IniRead, Excel_Filename,        %mvinifile%, Coord, Excel_Filename
    IniRead, Chk_GoogleSpr,         %mvinifile%, Coord, Chk_GoogleSpr
    IniRead, GoogleSpr_User,        %mvinifile%, Coord, GoogleSpr_User
    IniRead, GoogleSpr_Pass,        %mvinifile%, Coord, GoogleSpr_Pass
    IniRead, GoogleSpr_SheetName,   %mvinifile%, Coord, GoogleSpr_SheetName
    IniRead, Chk_GoogleGAE,         %mvinifile%, Coord, Chk_GoogleGAE
    IniRead, GAE_req_Server,        %mvinifile%, Coord, GAE_req_Server

    ; 初回起動の場合、適当に初期値を設定する(じ環境: 解像度1920x1400 推奨設定)。
    mvc_1st_run := 0
    if (!(x1 > 0 && x1 < 2000)) {
        mvc_1st_run := 1
        MsgBox 初回起動です。`nデフォルト設定します。
        x1                  := 900
        y1                  := 30
        x2                  := 1400
        y2                  := 400
        ChkJpg              := 1
        ChkOCR              := 0
        ChkAppend_OneText   := 1
        TxtAppend_Filename   = mvcap.log  ; MxE Vendor Window Capture
        ChkAdditionalCap    := 0
        AddX1               := 800
        AddY1               := 400
        AddX2               := 1200
        AddY2               := 600
        CapHotkey           := "~SC010" ; Qキー(透過)
        AdjustX             := 900
        Append_HTML         := 1
        Append_BaseDir      := Eソレス-00
        ChkDebug            := 0
        MoE_UserdataDir     =
        Chk_Excel           := 0
        Excel_Filename      =
        Chk_GoogleSpr       := 0
        GoogleSpr_User      =
        GoogleSpr_Pass      =
        GoogleSpr_SheetName =
        Chk_GoogleGAE       := 0
        GAE_req_Server      = http://moe-vendor-search.appspot.com/
    }

    if (MoE_UserdataDir == "ERROR") {
        MoE_UserdataDir =
    }
    if (Excel_Filename == "ERROR") {
        Excel_Filename =
    }
    if (GoogleSpr_SheetName == "ERROR") {
        GoogleSpr_SheetName =
    }
    if (Chk_GoogleSpr ==  "ERROR") {
        Chk_GoogleSpr := 0
    }
    if (Chk_GoogleGAE ==  "ERROR") {
        Chk_GoogleGAE := 0
    }
    if (GoogleSpr_User == "ERROR") {
        GoogleSpr_User =
        GoogleSpr_Pass =
    } else if (GoogleSpr_User) {
        GoogleSpr_User := Crypt.Encrypt.StrDecrypt(GoogleSpr_User, str_magic, 5, 1) ;  decrypts the string using previously generated hash,AES_128 and MD5
        GoogleSpr_Pass := Crypt.Encrypt.StrDecrypt(GoogleSpr_Pass, str_magic, 5, 1) ;  decrypts the string using previously generated hash,AES_128 and MD5
    }
    if (GAE_req_Server == "ERROR") {
        GAE_req_Server =
    }
    ; 設定ダイアログ初期化
    Gui, CfgDlg:Add, Tab2, x2 h500 w400 vseltab, キャプチャ1|キャプチャ2|オプション

    Gui, CfgDlg:Tab, 1
    Gui, CfgDlg:Add, Button, x12 y450 w70 h30 +Default gBtnOK, &OK

    Gui, CfgDlg:Add, CheckBox, x12  y40  w220 h20 vChkJpg, 指定領域をキャプチャ・&Jpg保存する
    Gui, CfgDlg:Add, Button,  x270  y40   w70 h25 gBtnSetOCRCapCoord, 範囲指定
    Gui, CfgDlg:Add, Button,  x270  y60   w70 h25 gBtnPrvOCRCapCoord, プレビュー
    Gui, CfgDlg:Add, Text,     x12  y70   w90 h20 , 始点
    Gui, CfgDlg:Add, Text,     x22  y90   w60 h20 , X座標
    Gui, CfgDlg:Add, Text,     x22  y120  w60 h20 , Y座標
    Gui, CfgDlg:Add, Edit,     x72  y90   w40 h20 vx1, 
    Gui, CfgDlg:Add, Edit,     x72  y120  w40 h20 vy1, 
    Gui, CfgDlg:Add, Text,     x120 y70   w90 h20 , 終点
    Gui, CfgDlg:Add, Text,     x140 y90   w60 h20 , X座標
    Gui, CfgDlg:Add, Text,     x140 y120  w60 h20 , Y座標
    Gui, CfgDlg:Add, Edit,     x190 y90   w40 h20 vx2, 
    Gui, CfgDlg:Add, Edit,     x190 y120  w40 h20 vy2, 

    Gui, CfgDlg:Add, CheckBox, x12 y140 w220 h20 gChkOCR_Handler vChkOCR, 指定領域をキャプチャ・O&CR変換する
    ds1 := ChkOCR == 1 ? " " : "Disabled"
    ds2 := ChkAppend_OneText ? " " : "Disabled"
    Gui, CfgDlg:Add, CheckBox, x22 y160 w220 h20 %ds1% gChkAppendTT_Handler vChkAppend_OneText hwndHChkAppend_OneText, 結果をひとつのテキストに追記する(&A)
    Gui, CfgDlg:Add, Text,     x32 y180 w140 h20 %ds1% %ds2% hwndHStaticTT, テキストファイル名(&T):
    Gui, CfgDlg:Add, Edit,    x160 y180 w140 h20 %ds1% %ds2% hwndHEditTT vTxtAppend_Filename,

    ds4 := Append_HTML ? " " : "Disabled"
    Gui, CfgDlg:Add, CheckBox,  x12 y210 w100 h17 gChkAppend_HTML_Handler vAppend_HTML, HT&ML出力する
    Gui, CfgDlg:Add, Text,      x32 y230 w100 h20 %ds4% hwndHBasedir1 , ベースディレクトリ(&B) :
    Gui, CfgDlg:Add, Edit,     x160 y230 w140 h20 %ds4% hwndHBasedir2 vAppend_BaseDir, 
   ;Gui, CfgDlg:Add, Button,   x300 y245  w70 h20 %ds4% gBtnBaseDir, 参照

    ds5 := (Chk_Excel == 1 && ChkOCR) ? " " : "Disabled"
    Gui, CfgDlg:Add, CheckBox,  x12 y260 w100 h17 %ds1% gChk_Excel_Handler vChk_Excel hwndHExcel1, E&xcel出力する
    Gui, CfgDlg:Add, Text,      x32 y280 w100 h20 %ds5% hwndHExcel2 , ファイル名(&F) :
    Gui, CfgDlg:Add, Edit,     x160 y275 w140 h20 %ds5% hwndHExcel3 vExcel_Filename, 
    Gui, CfgDlg:Add, Button,   x300 y275  w50 h20 gBtnSelectExcel, 参照

    ds6 := (Chk_GoogleSpr && ChkOCR) ? " " : "Disabled"
    Gui, CfgDlg:Add, CheckBox,  x12 y300 w200 h17 %ds1% gChk_GoogleSpr_Handler vChk_GoogleSpr hwndHGoogle0, &Google SpreadSheetにアップする
    Gui, CfgDlg:Add, Text,      x32 y330 w140 h20 %ds6% hwndHGoogle1 , Google アカウント名(&A) :
    Gui, CfgDlg:Add, Edit,     x160 y325 w140 h20 %ds6% hwndHGoogle2 vGoogleSpr_User,
    Gui, CfgDlg:Add, Text,      x32 y360 w100 h20 %ds6% hwndHGoogle3 , パスワード(&P) :
    Gui, CfgDlg:Add, Edit,     x160 y355 w140 h20 %ds6% hwndHGoogle4 Password vGoogleSpr_Pass,
    Gui, CfgDlg:Add, Text,      x32 y390 w100 h20 %ds6% hwndHGoogle5 , シート名(&S) :
    Gui, CfgDlg:Add, Edit,     x160 y385 w140 h20 %ds6% hwndHGoogle6 vGoogleSpr_SheetName, 

    Gui, CfgDlg:Add, CheckBox,  x12 y410 w180 h17 %ds1% gChk_GoogleGAE_Handler vChk_GoogleGAE hwndHGoogleGAE0, Google App E&ngineにアップする
    ds7 := (Chk_GoogleGAE && ChkOCR) ? " " : "Disabled"
    Gui, CfgDlg:Add, Edit,     x32  y430 w200 h20 %ds7%          hwndHGAEServer1 vGAE_req_Server, 
    Gui, CfgDlg:Add, Button,   x300 y430  w50 h20 %ds7%  gBtnGAE hwndHGAEServer2, 開く(&E)

    Gui, CfgDlg:Add, Button,   x100 y450 w70 h30 +Cancel gBtnCancel, Cance&l

    Gui, CfgDlg:Tab, 2
    Gui, CfgDlg:Add, Button, x12 y450 w70 h30 gBtnOK, &OK
    ds3 := ChkAdditionalCap ? " " : "Disabled"
    Gui, CfgDlg:Add, CheckBox, x12  y40   gChkAdditionalCap_Handler vChkAdditionalCap hwndHChkAdditionalCap, 同時に他の領域も撮影する(&2)
    Gui, CfgDlg:Add, Button,   x270 y40  w70  h25 %ds3% hwndHCoord1  gBtnSetAdditionalCapCoord, 範囲指定
    Gui, CfgDlg:Add, Button,   x270 y60  w70  h25 %ds3% hwndHCoord1  gBtnPrvAdditionalCapCoord, プレビュー
    Gui, CfgDlg:Add, Text,     x12  y70  w90  h20 %ds3% hwndHCoord2  , 始点
    Gui, CfgDlg:Add, Text,     x22  y90  w60  h20 %ds3% hwndHCoord3  , X座標
    Gui, CfgDlg:Add, Text,     x22  y120 w60  h20 %ds3% hwndHCoord4  , Y座標
    Gui, CfgDlg:Add, Edit,     x72  y90  w40  h20 %ds3% hwndHCoord5  vAddX1, 
    Gui, CfgDlg:Add, Edit,     x72  y120 w40  h20 %ds3% hwndHCoord6  vAddY1, 
    Gui, CfgDlg:Add, Text,     x120 y70  w90  h20 %ds3% hwndHCoord7  , 終点
    Gui, CfgDlg:Add, Text,     x140 y90  w60  h20 %ds3% hwndHCoord8  , X座標
    Gui, CfgDlg:Add, Text,     x140 y120 w60  h20 %ds3% hwndHCoord9  , Y座標
    Gui, CfgDlg:Add, Edit,     x190 y90  w40  h20 %ds3% hwndHCoord10 vAddX2, 
    Gui, CfgDlg:Add, Edit,     x190 y120 w40  h20 %ds3% hwndHCoord11 vAddY2, 
    Gui, CfgDlg:Add, Text,     x12  y150, (OCRは行いません)

    Gui, CfgDlg:Add, Button,   x100 y450 w70 h30 gBtnCancel, Cance&l

    Gui, CfgDlg:Tab, 3
    Gui, CfgDlg:Add, Button, x12 y450 w70 h30 gBtnOK, &OK
    Gui, CfgDlg:Add, Text,      x12 y40 w150 h20 , MoEのuserdataディレクトリ(&U) :
    Gui, CfgDlg:Add, Edit,      x32 y60 w240 h20 vMoE_UserdataDir, 
    Gui, CfgDlg:Add, Button,   x280 y60  w50 h20 gBtnMoEDir, 参照

    Gui, CfgDlg:Add, Text,      x12  y90 w120 h20 , キャプチャホットキー(&H) :
    Gui, CfgDlg:Add, Edit,      x32 y110 w140 h20 vCapHotkey,

;    Gui, CfgDlg:Add, Button,    x12 y140 w200 h20 gOmakeAdjustX, ウィンドウのX座標位置合わせ(&W),
;    Gui, CfgDlg:Add, Edit,     x220 y140 w50 h20 vAdjustX,

    Gui, CfgDlg:Add, CheckBox,  x12 y170 w100 h20 vChkDebug, デバッグ(&D)
    Gui, CfgDlg:Add, Button,   x100 y450 w70 h30 gBtnCancel, Cance&l

    ; タスクトレイメニューの初期化
    Menu, Tray, Add ; Add Separator.
    Menu, Tray, Add, 設定(&T), MenuSettingDlg
    Menu, Tray, Add, デバッグ1(&1), MenuDebug1
    Menu, Tray, Add, Status, MenuStatDlg
    Menu, Tray, Check, Status

    if (mvc_1st_run) {
        Gosub, MenuSettingDlg
    }
    ; ホットキーの有効化
    if (CapHotkey) {
        Hotkey, %CapHotkey%, do_capture, On
    }

    if (Chk_GoogleSpr == 1 && GoogleSpr_Pass && GoogleSpr_User && GoogleSpr_SheetName) {
        if (PySockInit(GoogleSpr_User, GoogleSpr_Pass, GoogleSpr_SheetName) ) { ; 初回のみ
            MsgBox, Pythonソケット 初期化エラー!
        } else {
            py_init := True
        }
    }

    StatDlgFontSize = s9
    Gosub, Redraw_Stat_Dlg

#include Capture2Text_BackEnd.ahk

    if (new_subst_ver > 0) {
        TrayTip, yamvcからの通知, 定義ファイルを更新しました`n(シリアル: %new_subst_ver%), 5
    }
return

Redraw_Stat_Dlg:
    ; 状態ウィンドウ(ラベルが付けられない・・・)
    Gui StatDlg:Default
    enl_checked =
    if(StatDlgFontSize == "s16") {
        enl_checked = checked
    }
    Gui, StatDlg:Add, CheckBox,   x5 y260 w120  h20 vAlwaysOnTop gAlwaysOnTop_Handler, 手前(&A)
    Gui, StatDlg:Add, CheckBox, x132 y260 w120  h20 vDlgTrans gDlgTrans_Handler, 半透明(&T)
    Gui, StatDlg:Add, CheckBox,   x5 y285 w120  h20 vEnlargeFont gEnlargeFont_Handler %enl_checked%, 大(&B)
    Gui, StatDlg:Add, Text,      x60 y290 w200  h20 vCacheHitCount hwndHStaticCacheHit,
    Gui, StatDlg:Add, ListView,   x0   y0 w250 h160 Grid vlvwtask1, ID|Capture task
    Gui, StatDlg:Add, ListView,   x0 y170 w250  h90 Grid vlvwtask2, ID|OCR task
    Gui StatDlg:Font, %StatDlgFontSize%
    stat_pos := "x0 y570 h310 w570"
    lvheight := "h300"
    lvwidth := "w300"
    if(StatDlgFontSize == "s16") {
        stat_pos := "x0 y450 h460 w620"
        lvheight := "h450"
        lvwidth := "w350"
    }
    if (Chk_GoogleGAE) {
        clms = No|初見のアイテム (クラウドと連動中, wクリで修正)
    } else {
        clms = No|最後の変換結果 (wクリで修正)
    }
    Gui, StatDlg:Add, ListView, x260   y0 %lvwidth% %lvheight% Grid vlvwtask3 gRequestSubst, %clms%
    Gui, StatDlg:Show, NoActivate %stat_pos%, Status
    stat_active := 1

    ; リストを再構築する
    Gui, ListView, lvwtask3
    for idx, unreview_item_name in AryUnreview {
        LV_Insert(idx, "", idx, unreview_item_name)
        LV_Modify(idx, "Vis")
    }
return

GuiClose:
    Gui, StatDlg:Hide
    Gui, ReqDlg:Destroy         ; Alt-F4がハンドル出来ないorz
    stat_active := false
return

GuiApplyValue() {
    Global

    GuiControl, CfgDlg:, x1, %x1%
    GuiControl, CfgDlg:, y1, %y1%
    GuiControl, CfgDlg:, x2, %x2%
    GuiControl, CfgDlg:, y2, %y2%

    GuiControl, CfgDlg:, ChkJpg, %ChkJpg%
    GuiControl, CfgDlg:, ChkOCR, %ChkOCR%
    GuiControl, CfgDlg:, ChkAppend_OneText, %ChkAppend_OneText%
    GuiControl, CfgDlg:, TxtAppend_Filename, %TxtAppend_Filename%

    GuiControl, CfgDlg:, ChkAdditionalCap, %ChkAdditionalCap%
    GuiControl, CfgDlg:, addx1, %addx1%
    GuiControl, CfgDlg:, addy1, %addy1%
    GuiControl, CfgDlg:, addx2, %addx2%
    GuiControl, CfgDlg:, addy2, %addy2%

    GuiControl, CfgDlg:, CapHotkey, %CapHotkey%
    GuiControl, CfgDlg:, AdjustX, %AdjustX%

    GuiControl, CfgDlg:, Append_HTML, %Append_HTML%
    GuiControl, CfgDlg:, Append_BaseDir, %Append_BaseDir%
    GuiControl, CfgDlg:, ChkDebug, %ChkDebug%
    GuiControl, CfgDlg:, MoE_UserdataDir, %MoE_UserdataDir%

    GuiControl, CfgDlg:, Chk_Excel, %Chk_Excel%
    GuiControl, CfgDlg:, Excel_Filename, %Excel_Filename%

    GuiControl, CfgDlg:, Chk_GoogleSpr, %Chk_GoogleSpr%
    GuiControl, CfgDlg:, GoogleSpr_User, %GoogleSpr_User%
    GuiControl, CfgDlg:, GoogleSpr_Pass, %GoogleSpr_Pass%
    GuiControl, CfgDlg:, GoogleSpr_SheetName, %GoogleSpr_SheetName%

    GuiControl, CfgDlg:, Chk_GoogleGAE, %Chk_GoogleGAE%
    GuiControl, CfgDlg:, GAE_req_Server, %GAE_req_Server%
    return
}

WriteCfg2INI() {
    Global
    IniWrite, %x1%,                    %mvinifile%, Coord, x1
    IniWrite, %y1%,                    %mvinifile%, Coord, y1
    IniWrite, %x2%,                    %mvinifile%, Coord, x2
    IniWrite, %y2%,                    %mvinifile%, Coord, y2
    IniWrite, %ChkJpg%,                %mvinifile%, Coord, ChkJpg
    IniWrite, %ChkOCR%,                %mvinifile%, Coord, ChkOCR
    IniWrite, %ChkAppend_OneText%,     %mvinifile%, Coord, ChkAppend_OneText
    IniWrite, %TxtAppend_Filename%,    %mvinifile%, Coord, TxtAppend_Filename
    IniWrite, %ChkAdditionalCap%,      %mvinifile%, Coord, ChkAdditionalCap
    IniWrite, %AddX1%,                 %mvinifile%, Coord, AddX1
    IniWrite, %AddY1%,                 %mvinifile%, Coord, AddY1
    IniWrite, %AddX2%,                 %mvinifile%, Coord, AddX2
    IniWrite, %AddY2%,                 %mvinifile%, Coord, AddY2
    IniWrite, %CapHotkey%,             %mvinifile%, Coord, CapHotkey
    IniWrite, %AdjustX%,               %mvinifile%, Coord, AdjustX

    IniWrite, %Append_HTML%,           %mvinifile%, Coord, Append_HTML
    IniWrite, %Append_BaseDir%,        %mvinifile%, Coord, Append_BaseDir
    IniWrite, %ChkDebug%,              %mvinifile%, Coord, ChkDebug
    IniWrite, %MoE_UserdataDir%,       %mvinifile%, Coord, MoE_UserdataDir

    IniWrite, %Chk_Excel%,             %mvinifile%, Coord, Chk_Excel
    IniWrite, %Excel_Filename%,        %mvinifile%, Coord, Excel_Filename

    IniWrite, %Chk_GoogleSpr%,         %mvinifile%, Coord, Chk_GoogleSpr

    ; Iniファイルを書くときに暗号化する
    hash := Crypt.Encrypt.StrEncrypt(GoogleSpr_User, str_magic, 5, 1) ; encrypts string using AES_128 encryption and MD5 hash
    IniWrite, %hash%,        %mvinifile%, Coord, GoogleSpr_User
    hash := Crypt.Encrypt.StrEncrypt(GoogleSpr_Pass, str_magic, 5, 1) ; encrypts string using AES_128 encryption and MD5 hash
    IniWrite, %hash%,        %mvinifile%, Coord, GoogleSpr_Pass

    IniWrite, %GoogleSpr_SheetName%,   %mvinifile%, Coord, GoogleSpr_SheetName

    IniWrite, %Chk_GoogleGAE%,         %mvinifile%, Coord, Chk_GoogleGAE
    IniWrite, %GAE_req_Server%,        %mvinifile%, Coord, GAE_req_Server
}

Update_Task1(ID, caption) {
    Global lvwtask1
    Gui StatDlg:Default
    Gui, ListView, lvwtask1
    Loop, % LV_GetCount()
    {
        LV_GetText(lvres, A_Index, 1)
        if (lvres == ID ) {
            LV_Modify(A_Index, "", ID, caption)
            return
        }
    }
    LV_Insert(1, "", ID, caption)
}

Update_Task2(ID, caption) {
    Global lvwtask2
    Gui StatDlg:Default
    Gui, ListView, lvwtask2
    Loop, % LV_GetCount()
    {
        LV_GetText(lvres, A_Index, 1)
        if (lvres == ID ) {
            LV_Modify(A_Index, "", ID, caption)
            return
        }
    }
    LV_Insert(1, "", ID, caption)
}

Update_ItemList1(ary_text) {
    Global lvwtask3

    Gui StatDlg:Default
    Gui, ListView, lvwtask3

    ; 全て削除する
    LV_Delete()

    ; リストから名称を追加する
    for idx, rec in ary_text {
        parse_price_item(rec, dummy, item_name)
        LV_Insert(idx, "", idx, item_name)
       ;dout(A_ThisFunc . " add: " . idx )
    }
}

; 未レビュー品の検索
unreview_get(itemname) {
    Global AryUnreview
    for idx, elm in AryUnreview {
        if (itemname == elm) {
            return 1
        }
    }
    return 0
}
unreview_put(itemname) {
    Global AryUnreview
    for idx, elm in AryUnreview {
        if (itemname == elm) {
            return 1
        }
    }
    AryUnreview.Insert(itemname)
    return 0
}

RequestedItems_find(item_name, aryRequestedItems) {
    for ri, relm in aryRequestedItems {
        if (relm == item_name) {
            return ri
        }
    }
    return 0
}

; データベースに名前が登録されているか問い合わせて、無かった場合のみ追加表示する。
Update_ItemList2(ary_text, ary_bmp) {
    Global lvwtask3, GAE_req_Server, Unreview_count, AryUnreviewBMP, TotalItems

    aryRequestedItems := {}
    aryRequestedItems_BMP := {}     ; このトランザクションで要求したファイル名の配列
    reclist =
    for idx, rec in ary_text {
        ; 品名と価格を分割
        parse_price_item(rec, dummy, item_name)
        if (!item_name) {
            continue
        }
        TotalItems += 1
        item_name := RegExReplace(item_name, "`r", "")
        item_name := RegExReplace(item_name, "`n", "")
        item_name := RegExReplace(item_name, "[ ]+$", "")
        item_name := RegExReplace(item_name, "\([0-9]+/[0-9]+\)", "")
        item := url_justify(item_name)
        item_name := UriDecode(item)

        ; すでに追加されたアイテムは照合要求しない。
        if (RequestedItems_find(item_name, aryRequestedItems) != 0) {
            continue
        }

        reclist .= item_name . ","
        aryRequestedItems.Insert(item_name)

        ; 画像ファイル名を逃がす
        from_fname := ary_bmp[idx]
        aryRequestedItems_BMP.Insert(from_fname)
        dout(A_ThisFunc " " idx ": item: " item_name " BMP: " from_fname)
    }

    GAE_req_Server := Trim(GAE_req_Server, " `t/")
    url := GAE_req_Server . "/adm/VerifyName"
    verify_req_file := "_tmp_verify_name_req.txt"
    FileDelete, %verify_req_file%
    FileAppend, verify_name_req_start`,, %verify_req_file%
    FileAppend, %reclist%, %verify_req_file%
    FileAppend, verify_name_req_end`,, %verify_req_file%
    Loop
    {
        ; サーバにmemcache照合を要求する
        text_res := Post_Image(url, "records", verify_req_file)
        if (!text_res) {
            dout(A_ThisFunc " VerifyNameエラー: GAEのmemcache照合に失敗しました(結果がありません)。")
            return
        }

       ;dout(A_ThisFunc " VerifyName result: " text_res)
        if (InStr(text_res, "-1,0,")) {
            dout(A_ThisFunc " サーバはキャッシュを準備中です")
            Sleep, 10000
            continue
        }

        if (InStr(text_res, "Error 414")) {
            dout(A_ThisFunc " VerifyNameエラー: リクエストが長すぎます")
            return
        }
        if (InStr(text_res, "That’s an error.")) {
            dout(A_ThisFunc " VerifyNameエラー: GAEからのエラーで照合失敗。デバッグログ参照。")
            FileAppend, % text_res, VerifyName_Error.txt
            return
        }
        break
    }

    ary_line := {}
    Loop, Parse, text_res, `n
        ary_line.insert(A_LoopField)
    if (ary_line.MaxIndex() <= 0) {
        return
    }
    if (ary_line.MaxIndex() > 16+1) {
        dout(A_ThisFunc " Error fetching result(" ary_line.MaxIndex() ")")
        return
    }

    ; 結果を分析して未レビュー品を抽出し、リストに追加する
    for tidx, item_line in ary_line {
        if (StrLen(item_line) == 0) {
            continue
        }
        if (InStr(item_line, "verify_name_result_")) {
            continue
        }
        field_cnt := 0
        Loop, Parse, item_line, `,
        {
            if (A_Index == 1) {
                item_found := A_LoopField
                field_cnt++
            }
            if (A_Index == 2) {
                review := A_LoopField
                field_cnt++
            }
            if (A_Index == 3) {
                item_name := A_LoopField
                field_cnt++
            }
        }
        if (field_cnt != 3) {
            dout(A_ThisFunc " VerifyNameエラー: 不正行: " item_line)
            continue
        }
        if (item_found == 1 && review > 0) {
            continue
        }

        ; 本当に問い合わせた内容か確認する
        item_name := RegExReplace(item_name, "\?", "")
        request_index := RequestedItems_find(item_name, aryRequestedItems)
        if (!request_index) {
            dout(A_ThisFunc " Error: " item_name " was not found on aryRequestedItems" )
            continue
        }

        ; すでに問い合わせ、リストに済み？
        if (unreview_get(item_name)) {
            dout(A_ThisFunc " Warning: " item_name " was already added into List." )
            continue
        }

        ; 画像ファイルを逃がす
        from_fname := aryRequestedItems_BMP[request_index]
        FileGetSize, numFileSize, % from_fname
        if (ErrorLevel) {
            dout(A_ThisFunc " エラー: 修正依頼のBitmapファイル'" from_fname "' (" request_index "): 無し")
            continue
        }

        ; 問い合わせ済みとする。
        unreview_put(item_name)

        dout(A_ThisFunc " item: " . item_name . " item_found: " . item_found . " review: " . review)

        ; ListViewに追加する。
        Gui StatDlg:Default
        Gui, ListView, lvwtask3

        Unreview_count++
        LV_Insert(Unreview_count, "", Unreview_count, item_name)
        LV_Modify(Unreview_count, "Vis")

        to_fname := "Output/Unreview-" . Unreview_count . ".BMP"
        FileDelete, %to_fname%
        FileCopy,   %from_fname%, %to_fname%, 1
        AryUnreviewBMP.Insert(to_fname)
        dout(A_ThisFunc " " to_fname "(" from_fname ") was added into Unreview bitmap file name list.")


    }
    if (AryUnreviewBMP.MaxIndex() != AryUnreview.MaxIndex()) {
        dout(A_ThisFunc " Warning, Index Unreview array (name and bitmap filename) was mismatch")
    }

    CacheHit := TotalItems - Unreview_count
    SetFormat, Float, 3.0
    missratio := Unreview_count / TotalItems * 100
    SetFormat, Float, 0.6
    msg = cache Miss:%Unreview_count%(%missratio%`%) Hit:%CacheHit%/%TotalItems%
    dout(A_ThisFunc " " msg)
    GuiControl, StatDlg:, CacheHitCount, %msg%
}

; デバッグ処理: 修正依頼の配列を全部ダンプする
MenuDebug1:
;+F4::    ; Shift - F4: debug
    if (!Chk_GoogleGAE) {
        return
    }
    FileDelete, AryUnreview.log
    for k,v in AryUnreviewBMP {
        val := k "`t" AryUnreview[k] "`t" v
        FileAppend, % val "`n", AryUnreview.log
    }
return

; 修正依頼ダイアログを開いたときの動作
RequestSubst:

    dout("RequestSubst double clicked index: " A_EventInfo)

    if (Chk_GoogleGAE) {
        last_img_fname := AryUnreviewBMP[A_EventInfo]
        text1 := AryUnreview[A_EventInfo]
    } else {
        if(!last_job) {
            MsgBox, エラー: ジョブは削除済み
            return
        }
        last_img_fname := last_job.ary_bmp_fname[A_EventInfo]
        text1 := last_job.ary_text_out[A_EventInfo]
    }
    dout("last_img_fname-" A_EventInfo ": " last_img_fname)
    dout("last_img_text_-" A_EventInfo ": " text1)
    parse_price_item(text1, dummy, item_name)
    if (reqdlg_cnt) {
        Gui, ReqDlg:Destroy
    }
    Gui, ReqDlg:Add, Button, x12 y160 w100  h30  Default gReqSubst_OK   vReqSubst_OK, 送信(&S)
    Gui, ReqDlg:Add, Button, x122 y160 w100 h30 -Default gReqSubst_Exit vReqSubst_Cancel, キャンセル(&C)

    Gui, ReqDlg:Add, Text,      x12 y10 w50 h20 , 元の画像
    Gui, ReqDlg:Add, Picture,   x12 y30 , % last_img_fname

    Gui, ReqDlg:Add, Text,      x52 y70 w200 h20 vReqText1, % item_name

    Gui, ReqDlg:Add, Text, x142 y100  w60 h20, 修正前(&B)
    Gui, ReqDlg:Add, Edit,  x42 y120 w250 h20 vReqText2, % item_name

    Gui, ReqDlg:Add, Text, x302 y100  w80 h20, = 修正候補(&A)
    Gui, ReqDlg:Add, Edit, x302 y120 w250 h20 vReqText3, % item_name

    Gui, ReqDlg:-MaximizeBox -MinimizeBox -SysMenu +OwnDialogs
    Gui, ReqDlg:Show, x500 y200, 誤字修正依頼
    reqdlg_cnt++
Return

url_justify(item) {
    item := Trim(item)

    item := RegExReplace(item, "'", "")
    item := RegExReplace(item, "`;", "")
    item := RegExReplace(item, "&", "＆")

    ; 銘を削る
    item := RegExReplace(item, "【MG品】", "")

    /*
        ; 耐久値で、変換に失敗したものを削る
        pos := RegExMatch(item, "\([0-9a-zA-Z｜ぁ-ーァ-ヶァ-ヴー一-龠∞/]+\)$", m_res)
        if (pos) {
            item := RegExReplace(item, "\([0-9a-zA-Z｜ぁ-ーァ-ヶァ-ヴー一-龠∞/]+\)$", "")
            m_res2 := RegExReplace(m_res, "[^0-9/]", "")
            item .= ":" . m_res2 ">"
        }
    */
    ; 異常な耐久度を削る(可能ならば)
    item := RegExReplace(item,  "/[0-9a-zA-Z｜ぁ-ーァ-ヶァ-ヴー一-龠∞]+\)", "/1)")
    item := RegExReplace(item, "\([0-9a-zA-Z｜ぁ-ーァ-ヶァ-ヴー一-龠∞]+/",  "(1/")

    item := RegExReplace(item, " ([0-9]+)\)", "(${1}/${1})")

    ; (/1)
    item := RegExReplace(item, "\(/([0-9]+)\)", "(${1}/${1})")

    ; 正常な耐久度を削る(可能ならば)
;   item := RegExReplace(item, "\([0-9]+/[0-9]+\)", "")

/*
    ; ペットや時の石のレベル値で、変換に失敗したものを削る
    ; 例: <破壊魔法:lvoij>
    buffi =
    Loop, Parse, item, `n, `r
    {
        pos := RegExMatch(A_LoopField, ":[a-zA-Z\.\\0-9]+>$", m_res)
        if (pos) {
            buffi2 := RegExReplace(A_LoopField, ":[a-zA-Z\.\\0-9]+>$", "")
            m_res := RegExReplace(m_res, "a0", "30")
            m_res := RegExReplace(m_res, "[^0-9\.]", "")
            buffi2 .= ":" m_res ">"
            buffi .= buffi2 . "`r`n"
            continue
        }
        buffi .= A_LoopField "`r`n"
    }
    item := buffi
*/

    ; トリミング
    item := RegExReplace(item, "[ ]+$", "")
    item := UriEncode(item)

    return item
}

makeProperBoundary(){ 
   Loop,26 
      n .= chr(64+a_index) 
   n .= "0123456789" 
   Loop,% StrLen(A_Now) { 
      Random,rnd,1,% StrLen(n) 
      Random,UL,0,1 
      b .= RegExReplace(SubStr(n,rnd,1),".$","$" (round(UL)? "U":"L") "0") 
   } 
   Return b 
} 

MimeType(ByRef Binary) { 
   MimeTypes:="424d image/bmp|4749463 image/gif|ffd8ffe image/jpeg|89504e4 image/png|4657530" 
          . " application/x-shockwave-flash|49492a0 image/tiff" 
   @:="0123456789abcdef" 
   Loop,8 
      hex .= substr(@,(*(a:=&Binary-1+a_index)>>4)+1,1) substr(@,((*a)&15)+1,1) 
   Loop,Parse,MimeTypes,| 
      if ((substr(hex,1,strlen(n:=RegExReplace(A_Loopfield,"\s.*"))))=n) 
         Mime := RegExReplace(A_LoopField,".*?\s") 
   Return (Mime!="") ? Mime : "application/octet-stream" 
}

ReqSubst_OK:

    GuiControl, Disable, ReqSubst_OK
    GuiControl, Disable, ReqSubst_Cancel

    GuiControlGet, ReqText1, , ReqText1
    GuiControlGet, ReqText2, , ReqText2
    GuiControlGet, ReqText3, , ReqText3

    if (ReqText2 == ReqText3) {
        GuiControl, Enable, ReqSubst_OK
        GuiControl, Enable, ReqSubst_Cancel
        return
    }

    ; ローカルの定義ファイルに追加
    ReqText1 := Trim(ReqText1)
    ReqText2 := Trim(ReqText2)
    ReqText3 := Trim(ReqText3)
    subdata := ReqText2 . " = " . ReqText3
    append_subst(subdata)
    subList.Insert(subdata)

    ReqText1 := url_justify(ReqText1)
    ReqText2 := url_justify(ReqText2)
    ReqText3 := url_justify(ReqText3)

    ; クラウドのデータベースに登録する
    pwhr := ComObjCreate("WinHttp.WinHttpRequest.5.1") ; Create WinHttpRequest object
    req := postsubst_mainte_Server "?item_name_orig=" ReqText1 "&item_name_from=" ReqText2 "&item_name_to=" ReqText3 "&post_only=1&"
    pwhr.Open("POST", req) ; Initialize an HTTP request.
    pwhr.Send()
    dbkey := pwhr.ResponseText
    dout("PSOT Result:" dbkey)

    ; クラウドにBMPをアップロードする(UTF-8と一緒に送信できない)
    ResponseText := Post_with_Image(postsubst_mainte_Server, last_img_fname, dbkey)

    html_res := ResponseText
    FileAppend, % html_res, put_subst_res.html

    GuiControl, Enable, ReqSubst_OK
    GuiControl, Enable, ReqSubst_Cancel

    Gui, ReqDlg:Destroy
    IfWinExist, % moe_win
        WinActivate, % moe_win
return

ReqSubst_Exit:
;   Gui, ReqDlg:Cancel
    Gui, ReqDlg:Destroy
return

Delete_Task(ID) {
    Global lvwtask1, lvwtask2

    Gui StatDlg:Default
    Gui, ListView, lvwtask1
    Loop, % LV_GetCount()
    {
        LV_GetText(lvres, A_Index, 1)
        if (lvres == ID ) {
            LV_Delete(A_Index)
        }
    }
    Gui, ListView, lvwtask2
    Loop, % LV_GetCount()
    {
        LV_GetText(lvres, A_Index, 1)
        if (lvres == ID ) {
            LV_Delete(A_Index)
        }
    }
}

AlwaysOnTop_Handler:
    GuiControlGet, AlwaysOnTop, , AlwaysOnTop
    if (AlwaysOnTop) {
        Gui StatDlg:+AlwaysOnTop
    } else {
        Gui StatDlg:-AlwaysOnTop
    }
return

DlgTrans_Handler:
    GuiControlGet, DlgTrans, , DlgTrans
    if (DlgTrans) {
        WinSet, Transparent, 150
    } else {
        WinSet, Transparent, 255
    }
return

EnlargeFont_Handler:
    GuiControlGet, EnlargeFont, , EnlargeFont
    if (StatDlgFontSize == "s9") {
        StatDlgFontSize = s16
    } else {
        StatDlgFontSize = s9
    }
    Gui, StatDlg:Destroy
    Gosub, Redraw_Stat_Dlg
return

class capjob {

    __New(count, log_fname) {

        this.ID := count

        this.mvc_log_fname := log_fname

        this.bmp_fname := "Output/mvc" . this.ID
        this.ary_bmp_fname := {}

        this.svr := ""
        this.area := ""
        this.alter := ""
        this.address := ""
        this.xc := 0
        this.zc := 0

        return this
    }

    captureBMP() {
        Global x1, y1, x2, ChkOCR, ChkDebug

        if (!ChkOCR) {
            return
        }
        Update_Task1(this.ID, "BMP撮影開始")
        dout(A_ThisFunc . " Started a job [" this.ID "]")

        y_offset := 47
        capture_HEIGHT := 22
        captured_count := 0
        Last_Y := Y1
        Loop, 16
        {

            ; アイテムの白い文字が出現する位置を調査し、撮影開始位置を調整する。
            search_start_x := X1
            search_start_y := Last_Y
            search_end_x   := search_start_x + 20
            search_end_y   := search_start_y + 20
            ;this.show_capture_preview(cnt, search_start_x, search_start_y, search_end_x, search_end_y)
            ;dout("PixelSearch try__: " search_start_x "," search_start_y "," search_end_x "," search_end_y)
            PixelSearch, OutX, OutY, search_start_x, search_start_y, search_end_x, search_end_y, 0xffffff
            if (ErrorLevel) {
                ;dout(A_ThisFunc . " [" . this.ID "," A_Index "] : 撮影中断(白文字無し)")
                Update_Task1(this.ID, A_Index . ": 撮影中断(白文字無し)")
                break
            }
            ;dout("PixelSearch found: " OutX "," OutY)
            Last_Y := OutY + 45

            ; 撮影
            start_x := OutX-5
            start_y := OutY-5
            end_x := X2
            end_y := start_y + capture_HEIGHT
            captureRect = % start_x ", " start_y ", " end_x ", " end_y    ; Form the screen capture rectangle
            fname := this.bmp_fname . "-" . A_Index . ".BMP"
            ; dout(A_ThisFunc . ": " captureRect " into " fname)
            CaptureScreen(captureRect, 0, fname)
            ; ファイル一個分
            this.ary_bmp_fname.Insert(fname)
            captured_count++
        }

        if (ChkDebug && captured_count) {
            ToolTip, % "ジョブ " this.ID " 撮影完了(" captured_count ")"
            SetTimer, ttoff, -1000
        }
    }

    show_capture_preview(cnt, sx, sy, ex, ey) {
        Global ChkDebug
        if (!ChkDebug) {
            return
        }
        ; Set the box color
        captureBoxColor := FFFFFF
        dlgname := "scpreview" . cnt
        Gui, %dlgname%:Color, %captureBoxColor%

        ;Gui, scPREDLG:+LastFound -Caption +ToolWindow
        Gui, %dlgname%:+LastFound -Caption +ToolWindow

        ; Set the box opacity
        CaptureBoxAlpha=40
        captureBoxAlphaScaled := Round((captureBoxAlpha / 100.0) * 255)
        WinSet, Transparent, %captureBoxAlphaScaled%

        jx1:=sx, jy1:=sy, jx2:=ex, jy2:=ey
        ; Display the capture box
        Gui, %dlgname%:Show, % "X" jx1 " Y" jy1 " W" jx2-jx1 " H" jy2-jy1
        Sleep, 300
        Gui, %dlgname%:Hide
        Sleep, 1000
    }
    hide_capture_preview(cnt) {
        dlgname := "scpreview" . cnt
        Gui, %dlgname%:Hide
    }

    ; 一回の撮影で出来たBitmapファイルをすべて削除する。
    Clr_BMP() {
        for i, fname in this.ary_bmp_fname {
            FileDelete, % fname
            ;dout("Deleting file: " fname)
        }
    }

    ; OCR処理
    OCR() {
        Global ChkDebug, ChkOCR

        if (!ChkOCR) {
            return
        }
        ; 開始時間
        Update_Task2(this.ID, "OCR開始")
        if(ChkDebug){
            ToolTip, % "ジョブ " this.ID " OCRを開始します。"
            SetTimer, ttoff, -1000
        }
        this.startTime := A_TickCount

        this.ary_text_out := {}
        this.out_buffer := doOCR(this.ary_bmp_fname, this.mvc_log_fname, this.ary_text_out)

        if (ChkDebug) {
            ToolTip, % "ジョブ " this.ID " OCR完了しました。"
            SetTimer, ttoff, -1000
        }

        ; 終了時間を記録する
        this.elapsedTime := A_TickCount - this.startTime
        Update_Task2(this.ID, "OCR完了 " this.elapsedTime " [msec]")

       ;this.Clr_BMP()
    }

    captureJpg() {
        Global x1, y1, x2, y2, ChkJpg, Append_BaseDir

        if (!ChkJpg) {
            return
        }

        Update_Task1(this.ID, "Jpg撮影1")
        captureRect = % x1 ", " y1 ", " x2 ", " y2    ; Form the screen capture rectangle

        fbuf = % "mvc-" this.out_file_key "-ocr.jpg"
        this.out_file_jpg1 := fbuf

        fpath = fbuf
        if(Append_BaseDir) {
            FileCreateDir, %Append_BaseDir%
            fpath = %Append_BaseDir%\%fbuf%
        }

        CaptureScreen(captureRect, false, fpath, 30)
        return
    }

    captureAdditionalJpg() {
        Global addx1, addy1, addx2, addy2, ChkAdditionalCap, Append_BaseDir

        if (!ChkAdditionalCap) {
            return
        }
        Update_Task1(this.ID, "Jpg撮影2")
        captureRect = % addx1 ", " addy1 ", " addx2 ", " addy2

        ; ベースファイル名
        fbuf = % "mvc-" this.out_file_key "-map.jpg"
        this.out_file_jpg2 := fbuf

        ; 相対パス
        fpath = fbuf
        if(Append_BaseDir) {
            FileCreateDir, %Append_BaseDir%
            fpath = %Append_BaseDir%\%fbuf%
        }
        this.map_file_path := fpath
        CaptureScreen(captureRect, false, fpath, 30)
        return
    }

    InitAreaInfo() {
        Global ChkOCR, MoE_UserdataDir

        if (!ChkOCR || !MoE_UserdataDir) {
            return
        }

        ; 設定が有効ならば、MoEのシステムログから得たエリア情報と座標を連結する。
        GetMoeCoord(svr, area, xc, zc)
        this.svr := svr
        this.area := area
        this.xc := xc
        this.zc := zc

        ; エリア情報がとれている場合、座標から家の番地を取得する
        if (this.area) {
            resa := GetMoeAddress(this.area, this.xc, this.zc)
            StringSplit, alter_addr, resa, "_"
            this.alter   := alter_addr1
            this.address := alter_addr2
        }
        dout(this.svr ", " this.area ", " this.alter ", " this.address ", " this.xc ", " this.zc)
    }

    RemoveIgnored() {
        for i, item_name in this.ary_text_out {
            if (strlen(item_name) < 3) {
                this.ary_text_out.Remove(i)
                dout("deleted empty record!")
            }
            if (InStr(item_name, "レコード ストーン")) {
                this.ary_text_out.Remove(i)
                dout("deleted record stone!")
            }
        }
    }

    MaskMGCreator() {
        Global ChkOCR, Chk_GoogleGAE

        if (!ChkOCR) {
            return
        }
        for i, item in this.ary_text_out {
            chg := Delete_Weapon_Creator(item)
            this.ary_text_out[i] := chg
            if (chg != item) {
                ;dout(A_ThisFunc ": masked creator: " . chg)
            }
        }

        if (Chk_GoogleGAE) {
            Update_ItemList2(this.ary_text_out, this.ary_bmp_fname)
        } else {
            Update_ItemList1(this.ary_text_out)
        }
    }

    Export_TextLog() {
        Global ChkOCR, ChkDebug, ChkAppend_OneText, TxtAppend_Filename, mvc_log_one_fname

        if (!(ChkOCR && ChkAppend_OneText == 1 && TxtAppend_Filename)) {
            return  ; 設定は無効。
        }

        Update_Task2(this.ID, "ログ出力中")

        dd := this.out_text_date ; 日付
        for i, item in this.ary_text_out {
            ; 品名と価格を分割
            parse_price_item(item, price, itemname)

            ; タブ区切りのテキストファイル
            wbuf := % dd "`t" this.svr "`t" this.area "`t" this.alter "`t" this.address "`t" this.xc "`t" this.zc "`t" price "`t" itemname "`n"
            FileAppend, % wbuf, % mvc_log_one_fname
        }
    }

    Export_HTML() {
        Global Append_HTML

        if (!Append_HTML) {
            return
        }
        Update_Task2(this.ID, "HTML出力中")

        FileGetSize, hsize, % this.html_fname
        if (ErrorLevel) {
            FileAppend, <table>, % this.html_fname
        }
        hbuf1 := "<tr><td rowspan=4><img src=" this.out_file_jpg1 "></td></tr>`n"
        hbuf1 .= "<tr><td>          <img src=" this.out_file_jpg2 "></td></tr>`n"
        hbuf1 .= "<tr><td><pre>" this.out_text_date "</pre>         </td></tr>`n"
        hbuf2=
        for i, item in this.ary_text_out {
            buf3 := item
            buf3 := RegExReplace(buf3, ">", "&gt")
            buf3 := RegExReplace(buf3, "<", "&lt")
            hbuf2 .= buf3 . "`n"
        }
        hbuf1 .= "<tr><td><pre><B>" this.svr "<BR>" this.area "<BR>最寄り:" this.alter "<BR>" this.address "<BR>" this.xc "," this.zc "</B>`n" hbuf2 "</pre>            </td></tr>`n"
        FileAppend, %hbuf1%, % this.html_fname
    }

    Export_Excel() {
        Global ChkOCR, Chk_Excel, Excel_Filename

        if (!(ChkOCR && Chk_Excel == 1 && Excel_Filename)) {
            return
        }

        if (!Xl) {
            Xl := getxl()
        }
        if (!Xl || !IsObject(Xl)) {
            Update_Task2(this.ID, "Excel COM初期化失敗！")
            return  ; Excel初期化失敗
        }

        Update_Task2(this.ID, "Excel出力中")

        ; パスが相対かチェック
        if (InStr(Excel_Filename, ":")) {
            fname := Excel_Filename
        } else {
            fname := % A_ScriptDir "\" Excel_Filename
        }
        ; ファイルを開く
        try {
            Workbook := Xl.Workbooks.Open(fname)
        } catch {
            MsgBox, Excelファイル' %fname% 'が見つかりません！
            return
        }

       ;Xl.Visible := True      ; for Debug

        ; 空いている行を探す
        cnt := 0
        while (Xl.Range("A" . A_Index).Value != "") {
            cnt++
        }
        inspos := cnt+1

        date := this.out_text_date ; 日付
        for i, buf in this.ary_text_out {

            buf := Delete_Weapon_Creator(buf)
            parse_price_item(buf, price, item)
            if (strlen(buf) < 3) {
                continue
            }
            Xl.Range("A" . inspos).Select
            Xl.Range("A" . inspos).Value := date
            Xl.Range("B" . inspos).Value := this.svr
            Xl.Range("C" . inspos).Value := this.area
            Xl.Range("D" . inspos).Value := this.alter
            Xl.Range("E" . inspos).Value := this.address
            Xl.Range("F" . inspos).Value := this.xc
            Xl.Range("G" . inspos).Value := this.zc
            Xl.Range("H" . inspos).Value := price
            Xl.Range("I" . inspos).Value := item
            inspos++
        }
        Workbook.Save()
        Workbook.Close()
        return
    }

    Export_GoogleSpr() {
        Global ChkOCR, Chk_GoogleSpr, GoogleSpr_Pass, GoogleSpr_User, GoogleSpr_SheetName, ChkDebug, MainSocket

        if (!(ChkOCR && Chk_GoogleSpr == 1 && GoogleSpr_Pass && GoogleSpr_User && GoogleSpr_SheetName)) {
            return  ; 設定は無効。
        }

        Update_Task2(this.ID, "CSV出力中")

        ; 一つのテキストファイルに書き出す。
        ; システムログを取得済みの場合、頭にタブ区切りで付与する。
        this.csvfname := "spr_tmp_" this.ID ".csv"
        FileDelete, % this.csvfname

        dd := this.out_text_date ; 日付
        wc := 0
        for i, item in this.ary_text_out {
            ; 品名と価格を分割
            parse_price_item(item, price, itemname)

            ; タブ区切りのテキストファイル
            wbuf := % dd "`t" this.svr "`t" this.area "`t" this.alter "`t" this.address "`t" this.xc "`t" this.zc "`t" price "`t" itemname "`n"
            ; Google SpreadSheetへアップするデータに蓄積する
            FileAppend, % wbuf, % this.csvfname
            wc++
        }
        if (!wc) {
            return
        }

        if (PySockInit(GoogleSpr_User, GoogleSpr_Pass, GoogleSpr_SheetName) ) { ; 初回のみ
            Update_Task2(this.ID, "ソケット初期化失敗！")
            return
        }

        if (ChkDebug) {
            ToolTip, Google SpreadSheetへアップ中・・・
            SetTimer, ttoff, Off
        }

        Update_Task2(this.ID, "スプレッドシート出力中")

        ; Google SpreadSheetへアップ
        SendData(MainSocket, "insert " this.csvfname "|")

        if (ChkDebug) {
            ToolTip, 終了.
            ToolTip
        }
    }

    Export_GAE() {
        Global Chk_GoogleGAE, ChkOCR

        if (!(Chk_GoogleGAE && ChkOCR)) {
            return  ; 設定は無効
        }

        Update_Task2(this.ID, "GAE出力中")

        gbuf_appended := {}
        gbuffer =
        for i, item in this.ary_text_out {
            ; 品名と価格を分割
            parse_price_item(item, price, item_name)
            item_name := RegExReplace(item_name, "`r", "")
            item_name := RegExReplace(item_name, "`n", "")
            item_name := RegExReplace(item_name, "[ ]+$", "")

            ; 既に追加されていたらスキップ
            found := 0
            for aid, _appended in gbuf_appended {
                pos := Instr(item_name, _appended)
                if(pos && strlen(item_name) == strlen(_appended)) {
                    found := 1
                    ;dout("Found already appended: " item_name ", " _appended)
                    break
                }
            }
            if(found == 1) {
                continue
            }
            gbuffer .= price "`t" item_name "`n"
            gbuf_appended.Insert(item_name)
        }
        dout (A_ThisFunc " gbuffer: " gbuffer)

        if (!Strlen(gbuffer)) {
            dout (A_ThisFunc  " No item!")
            return
        }

        ; クラウドにアップする
        iServer := server_to_int(this.svr)
        iArea   := area_to_int(this.area)
        iAlter  := alter_to_int(iArea, this.alter)
        if (this.map_file_path) {
            this.post_to_gae_img()
        }
        this.post_to_gae(iServer, iArea, iAlter, gbuffer )
    }

    post_to_gae(server, area, alter, item) {
        Global GAE_req_Server

        if (Strlen(GAE_req_Server) < 10) {
            MsgBox, クラウド サイトの URLを指定してください。
            return
        }
       ;dout(A_ThisFunc " PostData: " item)

        ; DBに入れたらあかん文字
        item := RegExReplace(item, "'", "")
        item := RegExReplace(item, "`;", "")
        item := RegExReplace(item, "&", "＆")

        ; 銘を削る
        item := RegExReplace(item, "【MG品】", "")

    /*
        ; 耐久値で、変換に失敗したものを削る
        pos := RegExMatch(item, "\([0-9a-zA-Z｜ぁ-ーァ-ヶァ-ヴー一-龠∞/]+\)$", m_res)
        if (pos) {
            item := RegExReplace(item, "\([0-9a-zA-Z｜ぁ-ーァ-ヶァ-ヴー一-龠∞/]+\)$", "")
            m_res2 := RegExReplace(m_res, "[^0-9/]", "")
            item .= ":" . m_res2 ">"
        }
    */
        ; 異常な耐久度を削る(可能ならば)
        item := RegExReplace(item,  "/[0-9a-zA-Z｜ぁ-ーァ-ヶァ-ヴー一-龠∞]+\)", "/1)")
        item := RegExReplace(item, "\([0-9a-zA-Z｜ぁ-ーァ-ヶァ-ヴー一-龠∞]+/",  "(1/")

        item := RegExReplace(item, " ([0-9]+)\)", "(${1}/${1})")

        ; (/1)
        item := RegExReplace(item, "\(/([0-9]+)\)", "(${1}/${1})")

        ; 正常な耐久度を削る(可能ならば)
        item := RegExReplace(item, "\([0-9]+/[0-9]+\)", "")

        ; トリミング
        item := RegExReplace(item, "[ ]+$", "")

    ;   dout("PostData1: " item)
        item := Trim(item)          ; 左右の空白を削る

;       item := UriEncode(item)
        if (!StrLen(item)) {
            dout(A_ThisFunc ": No PostData!")
            return
        }

        xc := this.xc
        zc := this.zc
        address := this.address
        PostData = dummy=__dmy__&tick=%A_TickCount%&server=%server%&area=%area%&alter=%alter%&address=%address%&xc=%xc%&zc=%zc%&
        dout(PostData)
        Loop, Parse, item, `n, `r
        {
            sline := Trim(A_LoopField)
            if(StrLen(sline) == 0) {
                break
            }
            itemname =
            price = 0
            Loop, Parse, sline, `t
            {
                if (A_Index == 1) {
                    price := A_LoopField
                }
                if (A_Index == 2) {
                    itemname := A_LoopField
                    break
                }
            }
            recc := "____pri_" . A_Index . "=" . price . "&"
            PostData .= recc
            recc := "____rec_" . A_Index . "=" . itemname . "&"
            PostData .= recc
        }
        dout(A_ThisFunc " PostData2: " PostData)
        sess := "_tmp_postdata.txt"
        FileDelete, %sess%
        FileAppend, %PostData%, %sess%

/*
        pwhr := ComObjCreate("WinHttp.WinHttpRequest.5.1") ; Create WinHttpRequest object
        GAE_req_Server := Trim(GAE_req_Server, " `t/")
        req := GAE_req_Server . "/PostAHK?" . PostData
        dout(A_ThisFunc " PostData3: " req)

        pwhr.Open("POST", req) ; Initialize an HTTP request.
        pwhr.Send()
        html_res := pwhr.ResponseText ; get HTML
*/
        url := GAE_req_Server . "/PostAHK"

        html_res := Post_Image(url, "session_data", sess)
        if (ChkDebug || !InStr(html_res, "MVC_Insert_to_DB_OK")) {
            ; 何かしらエラー
            dout(html_res)
            FileAppend, %html_res%, gae_result.html
            FileAppend, <HR>, gae_result.html
        }
    }

    post_to_gae_img() {
        Global GAE_req_Server

        GAE_req_Server := Trim(GAE_req_Server, " `t/")
        url := GAE_req_Server . "/PostAHK_MapImage"

        html_res := Post_Image(url, "imgfile", this.map_file_path)
        if (ChkDebug || !InStr(html_res, "MVC_Insert_IMG_to_DB_OK")) {
            ; 何かしらエラー
            dout(html_res)
            FileAppend, %html_res%, gae_result.html
            FileAppend, <HR>, gae_result.html
        }
    }

    __Delete() {
        dout("OCR [" this.ID "] Destructor")

        this.Clr_BMP()

        cfname := this.csvfname
        FileDelete, % cfname

        Delete_Task(this.ID)
    }
}

ExitSub:
    ; ソケットを開いていれば閉じる
    if (py_init) {
        SendData(MainSocket, "py_exit")
        NormalClose()
    }
    if (IsObject(hFileSyslog)) {
        hFileSyslog.Close()
    }
    ExitApp
return

MenuSettingDlg:
    ; Generated using SmartGUI Creator 4.0
    ; ホットキーの無効化
    if (CapHotkey) {
        Hotkey, %CapHotkey%, do_capture, Off
    }
    Gui, CfgDlg:Show, , mvc:家ベンダ用スクショ・OCR
    GuiApplyValue()
Return

MenuStatDlg:
    Menu, Tray, ToggleCheck, Status
    if (stat_active) {
        Gui, StatDlg:Hide
        dout("stat hide")
        stat_active := false
    } else {
        Gui, StatDlg:Show, x0 %stat_pos%, Status
        dout("stat show")
        stat_active := true
    }
return

BtnMoEDir:
    FileSelectFolder, tmpMoE_UserdataDir, , , MoEのシステムログを検出するディレクトリを指定してください。
    if (tmpMoE_UserdataDir) {
        MoE_UserdataDir := tmpMoE_UserdataDir
        GuiControl, CfgDlg:, MoE_UserdataDir, %MoE_UserdataDir%
    }
return

BtnBaseDir:
    FileSelectFolder, tmpAppend_BaseDir, , 1+2+4, ファイル(大量に出ます)の出力先ディレクトリを指定してください。
    if (tmpAppend_BaseDir) {
        Append_BaseDir := tmpAppend_BaseDir
        GuiControl, CfgDlg:, Append_BaseDir, %Append_BaseDir%
    }
return

BtnSelectExcel:
    FileSelectFile, tmpExcelPath, , , 出力先エクセルファイル(既存)を指定してください。
    if (tmpExcelPath) {
        Excel_Filename := tmpExcelPath
        GuiControl, CfgDlg:, Excel_Filename, %Excel_Filename%
    }
return

BtnOK:
    Gui, CfgDlg:Submit
    Gui, CfgDlg:Hide
    WriteCfg2INI()
    ToolTip, リロードします ; ホットケー再設定がめどい
    Sleep, 500
    Reload
return

BtnGAE:
    cloud_url := GAE_req_Server
    Run, %ComSpec% /c start %cloud_url%,, Hide
return

#IfWinActive, ahk_class AutoHotkeyGUI
Esc::
#IfWinActive
BtnCancel:
    ; ホットキーの有効化
    if (CapHotkey) {
        Hotkey, %CapHotkey%, do_capture, On
    }
    Gui, CfgDlg:Hide
    Gui, Capture:Destroy
    sw1:=false, sw2:=false
    Gui, Capture:Hide
return

; 領域設定1
BtnSetOCRCapCoord:
    last_coord_set := 1
    SetCoord()
return

; 領域設定2
BtnSetAdditionalCapCoord:
    last_coord_set := 2
    SetCoord()
return

BtnPrvOCRCapCoord:
    sw1 := !sw1
    DispCoord(1, sw1)
return

BtnPrvAdditionalCapCoord:
    sw2 := !sw2
    DispCoord(2, sw2)
return

DispCoord(which_rect, _capture_Mode) {
    Global x1, y1, x2, y2, AddX1, AddX2, AddY1, AddY2

    if(_capture_Mode == 0) {
        Gui, Capture:Destroy
        return
    }

    ; Set the box color
    captureBoxColor := 0080FF
    Gui, Capture:Color, %captureBoxColor%

    ; Make the GUI window the last found window for use by the line below
    ; Also keep the window on top of other windows and don't show in the task bar
    ; Gui, Capture:+LastFound +AlwaysOnTop -Caption +ToolWindow
    Gui, Capture:+LastFound -Caption +ToolWindow

    ; Set the box opacity
    CaptureBoxAlpha=40
    captureBoxAlphaScaled := Round((captureBoxAlpha / 100.0) * 255)
    WinSet, Transparent, %captureBoxAlphaScaled%

    if (which_rect == 1) {
        jx1:=x1, jy1:=y1, jx2:=x2, jy2:=y2
    } else {
        jx1:=Addx1, jy1:=Addy1, jx2:=Addx2, jy2:=Addy2
    }
    ; Display the capture box
    Gui, Capture:Show, % "X" jx1 " Y" jy1 " W" jx2-jx1 " H" jy2-jy1

}

ChkOCR_Handler:
    GuiControlGet, stat, , ChkOCR
    if (stat) {
        GuiControl, Enable, %HChkAppend_OneText%
    } else {
        GuiControl, Disable, %HChkAppend_OneText%
    }
    Gosub, ChkAppendTT_Handler
    Gosub, Chk_Excel_Handler
    GoSub, Chk_GoogleSpr_Handler
    GoSub, Chk_GoogleGAE_Handler
return

; ChkAppend_OneText, 結果をひとつのテキストに追記する(&A)
ChkAppendTT_Handler:
    GuiControlGet, stat1, , ChkOCR
    GuiControlGet, stat2, , ChkAppend_OneText
    if (stat1 && stat2) {
        GuiControl, Enable, %HStaticTT%
        GuiControl, Enable, %HEditTT%
    } else {
        GuiControl, Disable, %HStaticTT%
        GuiControl, Disable, %HEditTT%
    }
return

ChkAdditionalCap_Handler:
    GuiControlGet, stat, , ChkAdditionalCap
    Loop, 11
    {
        chwnd_name = HCoord%A_Index%
        chwnd := %chwnd_name%
        if (stat) {
            GuiControl, Enable, %chwnd%
        } else {
            GuiControl, Disable, %chwnd%
        }
    }
return

ChkAppend_HTML_Handler:
    GuiControlGet, stat, , Append_HTML
    if (stat) {
        GuiControl, Enable,  %HBasedir1%
        GuiControl, Enable,  %HBasedir2%
    } else {
        GuiControl, Disable, %HBasedir1%
        GuiControl, Disable, %HBasedir2%
    }
return

Chk_Excel_Handler:
    GuiControlGet, stat1, , ChkOCR
    if (stat1) {
        GuiControl, Enable,  %HExcel1%
    } else {
        GuiControl, Disable,  %HExcel1%
    }

    GuiControlGet, stat2, , Chk_Excel
    if (stat1 && stat2) {
        GuiControl, Enable,  %HExcel2%
        GuiControl, Enable,  %HExcel3%
    } else {
        GuiControl, Disable, %HExcel2%
        GuiControl, Disable, %HExcel3%
    }
return

Chk_GoogleSpr_Handler:
    GuiControlGet, stat1, , ChkOCR
    if (stat1) {
        GuiControl, Enable,  %HGoogle0%
    } else {
        GuiControl, Disable,  %HGoogle0%
    }

    GuiControlGet, stat2, , Chk_GoogleSpr
    if (stat1 && stat2) {
        GuiControl, Enable, %HGoogle1%
        GuiControl, Enable, %HGoogle2%
        GuiControl, Enable, %HGoogle3%
        GuiControl, Enable, %HGoogle4%
        GuiControl, Enable, %HGoogle5%
        GuiControl, Enable, %HGoogle6%
    } else {
        GuiControl, Disable, %HGoogle1%
        GuiControl, Disable, %HGoogle2%
        GuiControl, Disable, %HGoogle3%
        GuiControl, Disable, %HGoogle4%
        GuiControl, Disable, %HGoogle5%
        GuiControl, Disable, %HGoogle6%
    }
return

Chk_GoogleSpr_Handler2(stat3) {
    Global
    Local hwndGoog

    Loop, 6
    {
        hwndGoog = HGoogle%A_Index%
        GuiControl, %stat3%, %hwndGoog%
    }
    return
}

Chk_GoogleGAE_Handler:
    GuiControlGet, stat2, , Chk_GoogleGAE
    if (stat2) {
        GuiControl,  Enable, %HGAEServer1%
        GuiControl,  Enable, %HGAEServer2%
    } else {
        GuiControl, Disable, %HGAEServer1%
        GuiControl, Disable, %HGAEServer2%
    }
return

; 指定座標をキャプチャしてOCR + jpg保存する。
do_capture:
    IfWinNotActive, % moe_win
    {
        return
    }
    _do_capture()
return

_do_capture() {
    Global job_count, mvc_log_fname, AryJob, TxtAppend_Filename, Append_BaseDir, ChkOCR, ChkAdditionalCap, ChkDebug, mvc_log_one_fname

    snd_path = %A_ScriptDir%\shatter.wav
    if (FileExist(snd_path)) {
        SoundPlay, snd_path
    } else {
        SoundBeep, 800, 200
    }

    if (CapHotkey) {
        Hotkey, %CapHotkey%, do_capture, Off
    }

    out_file_key = % A_YYYY "-" A_MM "-" A_DD "_" A_Hour A_Min A_Sec "-" job_count  ; ファイル名に付与する日付
    out_text_key = % A_YYYY "/" A_MM "/" A_DD " " A_Hour ":" A_Min ":" A_Sec  ; テキスト内に付与する区切りの日付時刻
    out_text_date = % A_YYYY "/" A_MM "/" A_DD  ; テキスト内に付与する区切りの日付

    cjob := new capjob(job_count++, mvc_log_fname)

    Update_Task1(cjob.ID, "撮影中・・・")

    ; パスを決める
    html_fname = mvc.html
    mvc_log_fname = mvc-%out_file_key%
    mvc_log_one_fname = %TxtAppend_Filename%
    if(Append_BaseDir) {
        FileCreateDir, %Append_BaseDir%
        html_fname          = % Append_BaseDir . "\" . html_fname
        mvc_log_fname       = % Append_BaseDir . "\" . mvc_log_fname
    }

    cjob.out_file_key       := out_file_key
    cjob.out_text_key       := out_text_key
    cjob.out_text_date      := out_text_date
    cjob.html_fname         := html_fname
    cjob.mvc_log_fname      := mvc_log_fname
    cjob.mvc_log_one_fname  := mvc_log_one_fname

    cjob.captureBMP()              ; 先に撮影を済ませる
    cjob.captureJpg()                ; jpgの保存
    cjob.captureAdditionalJpg()      ; 追加領域の保存

    if (CapHotkey) {
        Hotkey, %CapHotkey%, do_capture, On
        dout("ホットキーを有効化しました")
    }

    SetTimer, ttoff, -1000
    Update_Task1(cjob.ID, "撮影完了")
    AryJob.Insert(cjob)         ; ジョブの登録
    if (!timer_ScheduledOCR_run) {
        timer_ScheduledOCR_run := true
        SetTimer, ScheduledOCR, 100         ; 別スレッドでOCR変換を実行
    }
}

dout(val) {
    Global ChkDebug
    if (!ChkDebug) {
        return
    }
    OutputDebug % "[yamvc] " . val
}

ScheduledOCR:
    if (!AryJob.MaxIndex()) {
        timer_ScheduledOCR_run := false
        SetTimer, ScheduledOCR, Off
        return  ; 全部処理が終わったらタイマ削除
    }
    for idx, jj in AryJob {
        ; OCR実行
        jj.OCR()

        ; 終了処理
        captureFinished(jj)

        ; 最後に実行したジョブとして登録(ステータスウィンドウで使う)
        last_job := jj

        ; ジョブ配列から削除
        AryJob.Remove(idx)
    }
return

; OCR終了処理(OCRテキストを各種フォーマットへExportする)
captureFinished(job) {
    Global ChkDebug

    file_st_time := A_TickCount ; 開始時間を記録

    job.InitAreaInfo()      ; 座標からエリア情報を生成する
    job.RemoveIgnored()     ; 無視アイテムの除外
    job.MaskMGCreator()     ; 製作者名をマスクする
    job.Export_TextLog()    ; ログ出力
    job.Export_HTML()       ; HTML出力
    job.Export_Excel()      ; Excel出力
    job.Export_GoogleSpr()  ; Google SpreadSheet出力
    job.Export_GAE()        ; DB出力

    ; 完了報告
    file_elapsed := A_TickCount - file_st_time
    Update_Task2(job.ID, "処理完了 OCR: " job.elapsedTime "[msec] 他: " file_elapsed "[msec]")
    if (ChkDebug) {
        ToolTip, % "処理完了 ジョブ:" job.ID "`n    OCR処理時間:" job.elapsedTime " [msec]`n    ファイル処理時間:" file_elapsed " [msec]`n"
        SetTimer, ttoff, -1000
    }

    snd_path = %A_ScriptDir%\ocrfinish.wav
    if (FileExist(snd_path)) {
        SoundPlay, snd_path
    } else {
        SoundBeep, 600, 200
    }
    return
}

; Preset the rect of capture area
SetCoord() {
    Global

    MsgBox, キャプチャ範囲を設定します。`n開始位置をクリックして灰色の四角形が出た後、`nマウスを右下の終了位置方向へ向かって移動させ、`n終了位置で再度 クリックしてください。`n(キャンセルする場合は右クリックしてください)
    startCaptureMode1()
    return
}

#If (captureMode)
~LButton::
    if (captureMode == 1) {
        startCaptureMode2()
    } else {
        ; End capture mode
        endCaptureMode()

        applyCoord()
    }
return

ESC::
~RButton::
    ; Update the active capture point
    updateActiveCoordWithMousePos()

    ; End capture mode
    endCaptureMode()
    msgbox, 範囲指定をキャンセルしました。
return
#If

; Start capture mode
startCaptureMode1() {
    global
    Gui, Capture:Destroy

    ; Set the capture mode flag
    captureMode = 1

    ; Set the active capture corner to the bottom-right corner
    topLeftCoordActive = 0
}

startCaptureMode2() {
    global

    captureMode = 2

    ; Initialize the capture box coordinates
    MouseGetPos, cx1, cy1
    MouseGetPos, cx2, cy2

    ; Create a timer to update the capture box
    SetTimer, UpdateCaptureBox, %BOX_UPDATE_RATE%

    ; Make the first update immediate rather than waiting for the timer
    Gosub, UpdateCaptureBox
}

; Update the position of the capture box.
UpdateCaptureBox:
  ; Set the box color
  captureBoxColor := 0080FF
  Gui, Capture:Color, %captureBoxColor%

  ; Make the GUI window the last found window for use by the line below
  ; Also keep the window on top of other windows and don't show in the task bar
  Gui, Capture:+LastFound +AlwaysOnTop -Caption +ToolWindow

  ; Set the box opacity
  CaptureBoxAlpha=40
  captureBoxAlphaScaled := Round((captureBoxAlpha / 100.0) * 255)
  WinSet, Transparent, %captureBoxAlphaScaled%

  ; Update the active capture point
  updateActiveCoordWithMousePos()

  ; Bound the capture box coordinates
  if(topLeftCoordActive) {
    if(cx1 + 1 > cx2)
      cx1 := cx2 - 1

    if(cy1 + 1 > cy2)
      cy1 := cy2 - 1
  } else {
    if(cx2 - 1 < cx1)
      cx2 := cx1 + 1

    if(cy2 - 1 < cy1)
      cy2 := cy1 + 1
  }

  ; Display the capture box
  Gui, Capture:Show, % "X" cx1 " Y" cy1 " W" cx2-cx1 " H" cy2-cy1

  ; Handle the case where the capture ended but the timer still had one update left
  if(captureMode == 0) {
    Gui, Capture:Destroy
    return
  }

return

; Update the active capture coordinates with the current mouse position
updateActiveCoordWithMousePos() {
  MouseGetPos, x, y

  setActiveCaptureCoords(x, y)

} ; updateActiveCoordWithMousePos


; Set the active capture coordinates
setActiveCaptureCoords(x, y) {
    global

    if(topLeftCoordActive) {
        cx1 := x
        cy1 := y

        if(moveBothCorners) {
            cx2 := cx1 + bothCornersWidth
            cy2 := cy1 + bothCornersHeight
        }
    } else {
        cx2 := x
        cy2 := y

        if(moveBothCorners) {
            cx1 := cx2 - bothCornersWidth
            cy1 := cy2 - bothCornersHeight
        }
    }
}

; End COR capture mode
endCaptureMode() {
    global

    ; Clear the capture mode flag
    captureMode = 0

    ; Stop the timer that updates the capture box
    SetTimer, UpdateCaptureBox, Off

    ; Remove the capture box
    Gui, Capture:Destroy

    ; Update the active capture point
    updateActiveCoordWithMousePos()

}

applyCoord() {
    Global

    ; End capture mode

    ; 値を引っ張る
    if (last_coord_set == 1) {
        x1 := cx1
        y1 := cy1
        x2 := cx2
        y2 := cy2
    } else if (last_coord_set == 2) {
        addx1 := cx1
        addy1 := cy1
        addx2 := cx2
        addy2 := cy2
    }
    GuiApplyValue()

    ToolTip, % "座標を指定しました。`n  X:  " cx1 "," cy1 "`n  Y:  " cx2 "," cy2 "`n設定先:" last_coord_set
    SetTimer, ttoff, -3000
}

ttoff:
    ToolTip
return

OmakeAdjustX:
    MsgBox, , おまけ機能
        , ベンダウィンドウを{%AdjustX%,0}の位置へ移動します。`n左角にベンダウィンドウを寄せてください。`n(OK押してから3秒後に開始)

    ToolTip, 3
    Sleep, 1000
    ToolTip, 2
    Sleep, 1000
    ToolTip, 1
    Sleep, 1000
    ToolTip

    ; 掴む
    corner_x := 15
    Click, ,  %corner_x%, 11, , , D

    ; 離す
    mvx2 := AdjustX + corner_x
    Click, , %mvx2%, 11, , , U
return

GetMoESystemLog() {
    Global MoE_UserdataDir, ChkOCR
    static moe_syslog_fname
    if (moe_syslog_fname) {
        return moe_syslog_fname
    }
    if (!ChkOCR or !MoE_UserdataDir) {
        return
    }
    AryFilename := {}
    AryFileDate := {}
    ; Find file pattern
    pattern := % MoE_UserdataDir "\mlog_" SubStr(A_YYYY,3) "_" A_MM "_" A_DD "_0.txt"
    date_newest =
    date_newest_idx := 0
    Loop, %pattern%, 0, 1
    {
        AryFilename.Insert(A_LoopFileFullPath)
        FileGettime, buf, %A_LoopFileFullPath%, M
        if (buf > date_newest) {
            date_newest := buf
            date_newest_idx := A_Index
        }
        AryFileDate.Insert(buf)
    }
    moe_syslog_fname := AryFilename[date_newest_idx]
    return moe_syslog_fname
}

/*
    MoEのシステムログから、サーバ,エリア,座標を取得する。
 */
GetMoeCoord(ByRef Server, ByRef Area, ByRef xCoord, ByRef zCoord) {
    Global last_moe_syslog, hFileSyslog, newest_server, newest_coord, LastCoordFoundLine, LastCorrdFileName

    ; 最新のシステムログを取得する。
    fname := GetMoESystemLog()
    if (!fname) {
        dout("GetMoESystemLog fail")
        return
    }
    if (LastCorrdFileName != fname) {
        ; 読んだファイルのリセット(初回か、日付が変わった。)
        LastCoordFoundLine := 0
        LastCorrdFileName := fname
        dout(A_ThisFunc ": reading new file")
    }

    ; ファイル名から,現在ログイン中のキャラを得る
    if (InStr(fname, "\EMERALD_")) {
        Server = EMERALD
    }
    if (InStr(fname, "\DIAMOND_")) {
        Server = DIAMOND
    }
    if (InStr(fname, "\PEARL")) {
        Server = PEARL
    }

    FileEncoding , cp932    ; Sjisに設定
    if (last_moe_syslog != fname) {
        if (last_moe_syslog) {
            hFileSyslog.Close()
        }
        last_moe_syslog := fname
        hFileSyslog := FileOpen(fname, "r")
        if (!IsObject(hFileSyslog)) {
            dout(A_ThisFunc " failed to open file")
            FileEncoding , UTF-8
            return
        }
    }

    line_count := 0
    read_count := 0
    Loop, Read, %fname%
    {
        line_count++
        ; 前回読んだ行まで読みとばす
        if (LastCoordFoundLine > 0 && LastCoordFoundLine > A_Index) {
            continue
        }
        ; 先頭20文字をカット
        if(InStr(A_LoopReadLine, "に入りました")) {
            ;dout(A_LoopReadLine)
            newest_server := SubStr(A_LoopReadLine, 20)
        }
        if(InStr(A_LoopReadLine, "Server:")) {
            ;dout(A_LoopReadLine)
            newest_server := SubStr(A_LoopReadLine, 20)
        }
        if(InStr(A_LoopReadLine, "X:")
            && InStr(A_LoopReadLine, "Y:")
            && InStr(A_LoopReadLine, "Z:") ) {
            ;dout(A_LoopReadLine)
            newest_coord := SubStr(A_LoopReadLine, 20)
        }
        read_count++
    }
    LastCoordFoundLine := line_count
    dout(A_ThisFunc ": read count:" read_count " LastCoordFoundLine: " LastCoordFoundLine)

/*
Sample             (-->20文字)
13/02/17 04:08:17: 城下町ビスク 中央エリア 地域 [Server:PEARL]
13/02/17 00:57:07: X:29.93 Y:1.06 Z:33.42
13/02/23 03:47:18: ソレス渓谷(Ancient Age) に入りました
1                  20                    42
*/

    ; エリア情報を抽出する
    entpos := InStr(newest_server, "に入りました")
    if(entpos) {
        ; まだエリア情報がない(もしくは、取っていない) : エリアに入った情報だけ抜き出す。
        Area := SubStr(newest_server, 1, entpos-2)
       ;dout("newest_server: " newest_server " entpos: " entpos " area: " area)
    } else {
        pos := InStr(newest_server, "[")
        StringLeft, Area, newest_server, pos-5
    }

    ; 座標情報を抽出する
    if (newest_coord) {
        pos := InStr(newest_coord, "X:")
        xCoord := SubStr(newest_coord, pos+2)
        pos := InStr(xCoord, " ")
        StringLeft, xCoord, xCoord, pos-1

        pos := InStr(newest_coord, "Z:")
        zCoord := SubStr(newest_coord, pos+2)
    }

    ; サーバ・エリア情報と座標を連結する
    buf := % newest_server "," newest_coord

    FileEncoding , UTF-8
    return buf
}

GetMoeAddress_Init() {
    Global AryMoEAddress
    if (AryMoEAddress) {
        dout(A_ThisFunc " Re-Initializing.")
        ; return
    }

    AryMoEAddress := {}
    ; ファイル読み込み
    FileEncoding , cp932    ; Sjisに設定
    Loop, Read, moe_area.def
    {
        addr := {}
        Loop, Parse, A_LoopReadLine, `,
          addr.Insert(A_Index, A_LoopField)
        AryMoEAddress.Insert(addr)
    }
    FileEncoding , UTF-8
}

; 現在位置の最寄りの家の番地を取得する
GetMoeAddress(area, xcoord, zcoord) {
    Global AryMoEAddress
    if (!area, !xcoord || !zcoord) {
        return
    }

    ; 初回の場合、ファイルから番地定義を読み込み
    if (!AryMoEAddress) {
        GetMoeAddress_Init()
    }
    if (!AryMoEAddress.MaxIndex()) {
        dout(A_ThisFunc " Error AryMoEAddress is nil")
        return
    }

    ; 最寄り番地を得る
    min_distance := -1
    retval =
    for i, v in AryMoEAddress {
        if (!InStr(v[1], area)) {
            continue
        }
        xdiff := xcoord - v[4]
        zdiff := zcoord - v[5]

        distance := Sqrt(xdiff*xdiff + zdiff*zdiff)
        if (min_distance == -1 || min_distance > distance) {
            min_distance := distance
            retval := v[2] "_" v[3] ; 最寄りアルター
        }
    }
    return retval
}

getxl() {
    Global Xl
    if (Xl) {
        return Xl
    }
    try {
        Xl := ComObjActive("Excel.Application")
    } catch {
        Xl := ComObjCreate("Excel.Application")
    }
    return Xl
}


; MG商品の銘と思しき箇所を削る
Delete_Weapon_Creator(str_in) {
    if (!InStr(str_in, "<") && !InStr(str_in, ">")) {
        return str_in
    }
    if (InStr(str_in, "テレポート")) {
        return str_in
    }
    if (InStr(str_in, "悟り")) {
        return str_in
    }
    if (InStr(str_in, "賢者")) {
        return str_in
    }
    if (InStr(str_in, "時の石")) {
        return str_in
    }
    if (InStr(str_in, "装備")) {
        return str_in
    }
    if (InStr(str_in, "地図")) {
        return str_in
    }
    if (InStr(str_in, "ノアゲート")) {
        return str_in
    }
    if (InStr(str_in, "アニマル ケイジ")) {
        return str_in
    }
    if (InStr(str_in, "古文書")) {
        return str_in
    }
    if (InStr(str_in, "魚拓")) {
        return str_in
    }
    if (InStr(str_in, "ホムンクルス人形")) {
        return str_in
    }
    if (InStr(str_in, "レシピ ノート")) {
        return str_in
    }
    if (InStr(str_in, "トレジャー マップ")) {
        return str_in
    }
    if (InStr(str_in, "ハウスキッ")) {
        return str_in
    }
;   ret := RegExReplace(str_in, "[<({]+[!-~ ｜ぁ-ーァ-ヶァ-ヴー一-龠]+[>)}]+", "【製作者銘削除】") ; 効き過ぎる

    ret := RegExReplace(str_in, "[<]+[!-~ ｜ぁ-ーァ-ヶァ-ヴー一-龠∞]+[>}]+", "【MG品】")

; msgbox % str_in "`n" ret
    return ret
}

parse_price_item(text, ByRef price, ByRef item) {
    pos := RegExMatch(text, "P)[ ]*Gold[\] ]*", mlen)
    if (!pos) {
        price := 0
        item := text
        return
    }
    item := SubStr(text, pos+mlen)
    item := Trim(item)

    pbuf := SubStr(text, 1, pos)
    pbuf := RegExReplace(pbuf, "^IJ", "[4")
    pbuf := RegExReplace(pbuf, "M", "4")
    pbuf := RegExReplace(pbuf, "^∞", "[9")
    pbuf := RegExReplace(pbuf, "@A", "@4")
    pbuf := RegExReplace(pbuf, "郎", "@3")
    pbuf := RegExReplace(pbuf, "G", "6")
    ; 数値だけ抜き出す(数字以外を削除)
    pbuf := RegExReplace(pbuf, "[^0-9]", "")

    if (pbuf=) {
        pbuf = 0
    }
    price := pbuf
}

server_to_int(svr) {
    if (svr == "EMERALD") {
        return 1
    }
    if (svr == "DIAMOND") {
        return 2
    }
    if (svr == "PEARL") {
        return 3
    }
    return 0
}

area_to_int(area) {
    if (Instr(area, "ソレス")) {
        return 1
    }
    if (Instr(area, "ユグ")) {
        return 2
    }
    if (Instr(area, "北東エリア")) {
        return 3
    }
    if (Instr(area, "南エリア")) {
        return 4
    }
    if (Instr(area, "西エリア")) {
        return 5
    }
    if (Instr(area, "シス")) {
        return 6
    }
    return 0
}

alter_to_int(area, alter) {
    if (area == 6) {
        if (alter == "A-1") {
            return 1
        }
        if (alter == "A-2") {
            return 2
        }
        if (alter == "B-1") {
            return 3
        }
        if (alter == "B-2") {
            return 4
        }
        if (alter == "B-3") {
            return 5
        }
        if (alter == "C-1") {
            return 6
        }
        if (alter == "C-2") {
            return 7
        }
        if (alter == "C-3") {
            return 8
        }
        if (alter == "D-1") {
            return 9
        }
        if (alter == "D-2") {
            return 10
        }
        if (alter == "E-1") {
            return 11
        }
        if (alter == "E-2") {
            return 12
        }
        if (alter == "F-1") {
            return 13
        }
        if (alter == "F-2") {
            return 14
        }
        if (alter == "G-1") {
            return 15
        }
    }
    if (alter == "メイン") {
        return 0
    }
    return alter
}

; modified from jackieku's code (http://www.autohotkey.com/forum/post-310959.html#310959)
UriEncode(Uri, Enc = "UTF-8") {
    StrPutVar2(Uri, Var, Enc)
    f := A_FormatInteger
    SetFormat, IntegerFast, H
    Loop
    {
    Code := NumGet(Var, A_Index - 1, "UChar")
    If (!Code)
        Break
    If (Code >= 0x30 && Code <= 0x39 ; 0-9
        || Code >= 0x41 && Code <= 0x5A ; A-Z
        || Code >= 0x61 && Code <= 0x7A) ; a-z
        Res .= Chr(Code)
    Else
        Res .= "%" . SubStr(Code + 0x100, -1)
    }
    SetFormat, IntegerFast, %f%
    Return, Res
}

UriDecode(Uri, Enc = "UTF-8") {
    Pos := 1
    Loop
    {
        Pos := RegExMatch(Uri, "i)(?:%[\da-f]{2})+", Code, Pos++)
        If (Pos = 0)
            Break
        VarSetCapacity(Var, StrLen(Code) // 3, 0)
        StringTrimLeft, Code, Code, 1
        Loop, Parse, Code, `%
            NumPut("0x" . A_LoopField, Var, A_Index - 1, "UChar")
        StringReplace, Uri, Uri, `%%Code%, % StrGet(&Var, Enc), All
    }
    Return, Uri
}

StrPutVar2(Str, ByRef Var, Enc = "") {
    Len := StrPut(Str, Enc) * (Enc = "UTF-16" || Enc = "CP1200" ? 2 : 1)
    VarSetCapacity(Var, Len, 0)
    Return, StrPut(Str, &Var, Enc)
}

check_software_update() {
    Global mainte_Server

    pwhr := ComObjCreate("WinHttp.WinHttpRequest.5.1") ; Create WinHttpRequest object
    pwhr.Open("Get", mainte_Server) ; Initialize an HTTP request.
    pwhr.Send()

    text_res := pwhr.ResponseText
    if (InStr(text_res, "404 Not Found")) {
        msgbox % 更新チェックエラー
        return False
    }
    FileRead, current_ver, version.txt
    if (text_res > current_ver) {
        return True
    }
    return False
}

; 定義ファイル更新チェック
check_subst_update() {
    Global subst_mainte_Server, getsubst_mainte_Server

    pwhr := ComObjCreate("WinHttp.WinHttpRequest.5.1") ; Create WinHttpRequest object
    pwhr.Open("Get", subst_mainte_Server) ; Initialize an HTTP request.
    pwhr.Send()

    text_res := pwhr.ResponseText
    if (InStr(text_res, "404 Not Found")) {
        return 0
    }
    FileRead, current_ver, version_subst.txt
    if (text_res <= current_ver) {
        ; 定義ファイル更新なし
        return 0
    }
    pwhr.Open("Get", getsubst_mainte_Server) ; Initialize an HTTP request.
    pwhr.Send()

    subst_body := Trim(pwhr.ResponseText)
    pos := InStr(subst_body, "#")
    if (pos > 1) {  ; 行頭がコメント以外？
        subst_body := SubStr(subst_body, 2) ; 行頭の制御文字カット
    }
    ; 定義ファイルの妥当性チェック
    pos := InStr(subst_body, "# This is the Capture2Text OCR substitutions file.")
    if (!pos) {
        ; 定義ファイルが不正: 何もしない
        FileAppend, %subst_body%, substitutions_invalid.txt
        return 0
    }
    ; 一応バックアップを取る
    FileMove, substitutions.txt, substitutions_bak-%current_ver%.txt, 1
    ; 定義ファイルに上書きする
    FileDelete, substitutions.txt
    FileEncoding , UTF-8
    FileAppend, %subst_body%, substitutions.txt

    ; 定義ファイルのバージョンを更新する
    FileDelete, version_subst.txt
    FileAppend, %text_res%, version_subst.txt

    TrayTip, yamvcからの通知, 定義ファイルを更新しました`n(シリアル: %text_res%), 5

    return text_res
}

; 定義ファイルに追加する
append_subst(data) {

    fboundary := "# yamvc_write_seek_end"
    bdsize := StrLen(fboundary) + 2

    FileCopy, "substitutions.txt", "substitutions-bakup.txt", 1

    FileEncoding , UTF-8
    HFile := FileOpen("substitutions.txt", "rw")
    if (!HFile) {
        return -1
    }

    FileSize := HFile.Length
    Loop
    {
        line := HFile.ReadLine()
        if (InStr(line, fboundary)) {
            NewSize := FileSize + StrLen(data) + 1
            HFile.Length := NewSize
            HFile.Seek((bdsize)*-1, 1)
            last_lines := {}
            pos := HFile.Tell()
            Loop
            {
                HFile.Seek(0, 1)
                if (HFile.AtEOF) {
                    break
                }
                line := HFile.ReadLine()
                last_lines.Insert(line)
            }
            HFile.Seek(pos, 0)
            HFile.WriteLine(data)
            for i,l in last_lines {
                HFile.Write(l)
            }
            break
        }
        line_len := StrLen(line)
        HFile.Seek(0, 1)
        if (HFile.AtEOF) {
            break
        }
    }
    HFile.Close()
    return 0
}

get_mimetype(img) {
    itypea := NumGet( img, 0, "UShort" )
    itypeb := NumGet( img, 2, "UShort" )
    mimetype := itypea = 0x4d42 ? "image/bmp"
    : itypea = 0x4947 && itypeb = 0x3846 ? "image/gif"
    : itypea = 0xd8ff && itypeb = 0xe1ff ? "image/jpeg"
    : itypea = 0x5089 && itypeb = 0x474e ? "image/png"
    : itypea = 0x4949 && itypeb = 0x2a ? "image/tiff"
    : itypea = 0x5746 && itypeb = 0x53 ? "application/x-shockwave-flash"
    : "application/octet-stream"
    return mimetype

}

Post_Image(url, field_name, file) {
    FileGetSize, size, % file
    VarSetCapacity( data, size + 4096, 0 )
    FileRead, img, % "*c " file

    mimetype := get_mimetype(img)

    boundary := "----" . HTTPRequest_MD5( boundary := file "?" A_Now A_MSec, StrLen( file ) + 18 << !! A_IsUnicode )
    headers := "Content-type: multipart/form-data; boundary=" boundary "`n"
    file := RegexReplace( "\" file, ".*\\" )

    ; form ペイロードの作成
    string =
    ( LTRIM
        --%boundary%
        Content-Disposition: form-data; name="%field_name%"; filename="%file%"
        Content-type: %mimetype%`n`n
    )

    ; イメージバイナリの挿入
    offset := StrPut( string, &data, StrLen( string ), "UTF-8" )
    DllCall( "RtlMoveMemory", "Ptr", &data + offset, "Ptr", &img, "Int", size )
    hooter := "`n--" boundary "--"
    size += offset + StrPut( hooter, &data + offset + size, StrLen( hooter ), "UTF-8" )

    headers .= "Content-Length: " size "`n`n"
    s := HTTPRequest( url, data, headers )
    return data
}

Post_with_Image(url, file, dbkey) {
    FileGetSize, size, % file
    VarSetCapacity( data, size + 4096, 0 )
    FileRead, img, % "*c " file

    mimetype := get_mimetype(img)

    boundary := "----" . HTTPRequest_MD5( boundary := file "?" A_Now A_MSec, StrLen( file ) + 18 << !! A_IsUnicode )
    headers := "Content-type: multipart/form-data; boundary=" boundary "`n"
    file := RegexReplace( "\" file, ".*\\" )
    file := RegexReplace( "/" file, ".*/" )

    string =
    ( LTRIM 
--%boundary%
Content-Disposition: form-data; name="post_only"

1
--%boundary%
Content-Disposition: form-data; name="key"

%dbkey%
--%boundary%
Content-Disposition: form-data; name="imgfile"; filename="%file%"
Content-Type: %mimetype%`n`n
    )

    offset := StrPut( string, &data, StrLen( string ), "UTF-8" )
    DllCall( "RtlMoveMemory", "Ptr", &data + offset, "Ptr", &img, "Int", size )
    hooter := "`n--" boundary "--"
    size += offset + StrPut( hooter, &data + offset + size, StrLen( hooter ), "UTF-8" )

    headers .= "Content-Length: " size "`n`n"
    s := HTTPRequest( url, data, headers )
    return data
}
